package jinyilw.swing.image;

import jinyilw.common.TextTools;
import jinyilw.common.file.FileTools;
import jinyilw.swing.ColorTools;
import jinyilw.swing.PixelsTools;
import jinyilw.swing.ResourceManager;
import jinyilw.swing.graphics.GraphicsTools;
import jinyilw.swing.i18n.IString;
import jinyilw.swing.i18n.LanguageTools;
import jinyilw.swing.visuals.Icomp.IFileChooser;
import jinyilw.swing.visuals.Rcomp.RFileChooser;

import javax.imageio.ImageIO;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.Area;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.ColorModel;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class ImageTools
{
	public final static String[] pictureExts = {"png", "jpg", "jpeg", "bmp"};
	private static final IString fileString = new IString("pictureFile", "图片文件",
			"Picture file");
	private static RFileChooser pictureOpenChooser;
	private static String currentPicturePath;
	private static String languageTag;

	private static int mediaTrackerID;
	private static final MediaTracker mediaTracker = new MediaTracker(new Component()
	{
	});

	private ImageTools()
	{
	}

	public static BufferedImage createTransparentImage(int width, int height)// 创建透明图像
	{
		return GraphicsTools.createCompatibleImage(width, height,
				Transparency.TRANSLUCENT);
	}

	public static BufferedImage createOpaqueImage(int width, int height)// 创建不透明图像
	{
		return GraphicsTools.createCompatibleImage(width, height,
				Transparency.OPAQUE);
	}
	public static Image openAndGetImage(String path, String title,
			Component com)
	{
		RFileChooser fileChooser = getPictureOpenChooser(null, title);
		if (path != null && !path.equals(currentPicturePath))
		{
			currentPicturePath = path;
			fileChooser.setCurrentDirectory(new File(path));
		}
		return ResourceManager
				.getBufferedImage(fileChooser.openAndGetOpenFile(com));
	}
	public static IFileChooser getPictureSaveChooser(String path, String title)
	{
		return new IFileChooser(FileTools.getUserFile(path), pictureExts,
				title);
	}
	public static IFileChooser getPictureSaveChooser(String path, IString title)
	{
		return new IFileChooser(FileTools.getUserFile(path), pictureExts,
				title);
	}
	public static RFileChooser getPictureOpenChooser(String path, String title)
	{
		if (pictureOpenChooser == null
				|| languageTag != LanguageTools.languageTag)
		{
			if (pictureOpenChooser != null)
				path = pictureOpenChooser.getCurrentDirectory()
						.getAbsolutePath();
			pictureOpenChooser = new RFileChooser(path);
			pictureOpenChooser.setAcceptAllFileFilterUsed(false);
			FileFilter igmFilter = new FileNameExtensionFilter(
					fileString.getI18nString(), pictureExts);
			pictureOpenChooser.addChoosableFileFilter(igmFilter);
			languageTag = LanguageTools.languageTag;
		}
		pictureOpenChooser.setDialogTitle(title);
		return pictureOpenChooser;
	}

	public BufferedImage createCompatibleImage(BufferedImage src)
	{
		if (src == null)
			return null;
		ColorModel dstCM = src.getColorModel();
		return new BufferedImage(dstCM,
				dstCM.createCompatibleWritableRaster(src.getWidth(),
						src.getHeight()),
				dstCM.isAlphaPremultiplied(), null);
	}

	public static BufferedImage getImageFromPixels(int[] pixels, int w, int h)
	{
		return getImageFromPixels(pixels, w, h, Transparency.OPAQUE);
	}

	public static BufferedImage getImageFromPixels(int[] pixels, int w, int h,
			int transparency)
	{
		if (pixels == null || w <= 0 || h <= 0 || pixels.length < w * h)
			return null;
		BufferedImage img = GraphicsTools.createCompatibleImage(w, h,
				transparency);
		img.setRGB(0, 0, w, h, pixels, 0, w);
		//		WritableRaster raster = img.getRaster();
		//		raster.setDataElements(0, 0, w, h, pixels);
		return img;
	}

	public static BufferedImage getUnshapedImage(Image src, int w, int h)
	{
		if (src == null)
			return null;
		if (w <= 0 || h <= 0)
			return null;
		int iw = src.getWidth(null), ih = src.getHeight(null);
		if (iw <= 0 || ih <= 0)
		{
			loadImage(src);
			iw = src.getWidth(null);
			ih = src.getHeight(null);
			if (iw <= 0 || ih <= 0)
				return null;
		}
		double dw = iw, dh = ih;
		if (dw / w > dh / h)
		{
			iw = w;
			ih = (int) (w / dw * dh);
		} else
		{
			ih = h;
			iw = (int) (h / dh * dw);
		}
		return getShapedImage(src, iw, ih);
	}

	public static BufferedImage getShapedImage(Image src, int width, int height)
	{
		if (src == null)
			return null;
		if (width <= 0 || height <= 0)
			return null;
		Image img = src;
		if (width != src.getWidth(null) || height != src.getHeight(null))
			img = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
		int transparency = Transparency.TRANSLUCENT;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		BufferedImage dest = GraphicsTools.createCompatibleImage(width, height,
				transparency);
		Graphics g = dest.createGraphics();
		g.drawImage(img, 0, 0, null);
		g.dispose();
		return dest;
	}

	public static BufferedImage toTransparentImage(Image src)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		BufferedImage dest = GraphicsTools.createCompatibleImage(width, height,
				Transparency.TRANSLUCENT);
		Graphics g = dest.createGraphics();
		g.drawImage(src, 0, 0, null);
		g.dispose();
		return dest;
	}

	public static BufferedImage toBufferedImage(Image src)
	{
		if (src == null)
			return null;
		if (src instanceof BufferedImage)
			return (BufferedImage) src;

		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		BufferedImage bimage = null;
		GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
		try
		{
			// Determine the type of transparency of the new buffered image
			int transparency = Transparency.OPAQUE;
			GraphicsDevice gs = ge.getDefaultScreenDevice();
			GraphicsConfiguration gc = gs.getDefaultConfiguration();
			bimage = gc.createCompatibleImage(
					width, height, transparency);
		} catch (HeadlessException ignored)
		{
		}

		if (bimage == null)
		{
			// Create a buffered image using the default color model
			int type = BufferedImage.TYPE_INT_RGB;
			bimage = new BufferedImage(width, height, type);
		}
		// Copy image to buffered image
		Graphics g = bimage.createGraphics();
		// Paint the image onto the buffered image
		g.drawImage(src, 0, 0, null);
		g.dispose();
		return bimage;
	}

	public static void saveImageToFile(Image image, File file, String ext)
	{
		if (image == null || file == null)
			return;
		if (ext == null)
			ext = "jpg";
		try
		{
			ImageIO.write(toBufferedImage(image), ext, file);
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}

	public static BufferedImage getScaleBufferedImage(Image src, float scale)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		width = (int) (width * scale);
		height = (int) (height * scale);
		return getShapedImage(src, width, height);
	}

	public static BufferedImage getContrastLightImage(Image src, float contrast,
			float lightness)
	{
		if (src == null)
			return null;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		PixelsTools.contrastLightFilter(pixels, contrast, lightness);
		int width = src.getWidth(null), height = src.getHeight(null);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		return getImageFromPixels(pixels, width, height, transparency);
	}

	public static BufferedImage getContrastImage(Image src, float contrast)
	{
		if (src == null)
			return null;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		PixelsTools.contrastFilter(pixels, contrast);
		int width = src.getWidth(null), height = src.getHeight(null);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		return getImageFromPixels(pixels, width, height, transparency);
	}

	public static BufferedImage getLightnessImage(Image src, float lightness)
	{
		if (src == null)
			return null;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		PixelsTools.lightnessFilter(pixels, lightness);
		int width = src.getWidth(null), height = src.getHeight(null);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		return getImageFromPixels(pixels, width, height, transparency);
	}

	public static BufferedImage getAlphaImage(Image src, int alpha)
	{
		if (src == null)
			return null;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		PixelsTools.alphaFilter(pixels, alpha);
		int width = src.getWidth(null), height = src.getHeight(null);
		return getImageFromPixels(pixels, width, height,
				Transparency.TRANSLUCENT);
	}

	public static BufferedImage getAverageLightImage(Image src, int average,
			int bright)
	{
		if (src == null)
			return null;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		PixelsTools.averageBrightFilter(pixels, average, bright);
		int width = src.getWidth(null), height = src.getHeight(null);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		return getImageFromPixels(pixels, width, height, transparency);
	}

	public static Image getBlurImage(Image src, int radius)
	{
		if (src == null || radius <= 0)
			return src;
		int[] pixels = PixelsTools.getPixelsFromImage(src);
		if (pixels == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		PixelsTools.fastBlurFilter(pixels, width, height, radius);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		return getImageFromPixels(pixels, width, height, transparency);
	}

	public static Image getShapedBlurImage(Image src, int width, int height,
			int radius)
	{
		if (src == null || radius <= 0)
			return src;
		return getBlurImage(getShapedImage(src, width, height), radius);
	}

	public static Image getColoredBlurImage(Image src, Color color, int radius)
	{
		if (src == null || radius <= 0)
			return src;
		return getBlurImage(getColoredImage(src, color), radius);
	}

	public static BufferedImage getColoredImage(Image src, Color color)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		if (color == null)
			color = Color.white;
		if (color.getAlpha() > 250)
			color = ColorTools.getAlphaColor(color, 125);
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		BufferedImage dest = GraphicsTools.createCompatibleImage(width, height,
				transparency);
		Graphics g = dest.createGraphics();
		g.drawImage(src, 0, 0, null);
		g.setColor(color);
		g.fillRect(0, 0, width, height);
		g.dispose();
		return dest;
	}

	public static BufferedImage getLogoImage(Image src, Image logoImg, int lw,
			int lh)
	{
		if (src == null)
			return null;
		int w = src.getWidth(null), h = src.getHeight(null);
		if (w <= 0 || h <= 0)
		{
			loadImage(src);
			w = src.getWidth(null);
			h = src.getHeight(null);
			if (w <= 0 || h <= 0)
				return null;
		}
		int transparency = Transparency.TRANSLUCENT;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		BufferedImage dest = GraphicsTools.createCompatibleImage(w, h,
				transparency);
		Graphics g = dest.getGraphics();
		g.drawImage(src, 0, 0, null);
		g.drawImage(logoImg, (w - lw) / 2, (h - lh) / 2, null);
		g.dispose();
		return dest;
	}

	public static BufferedImage getCompositeImage(Image startImg,
			Image middleImg, Image endImg, int w, int h)
	{
		int sw = startImg.getWidth(null), sh = startImg.getHeight(null);
		System.out.println(sw + ":" + sh);
		int ew = endImg.getWidth(null), eh = endImg.getHeight(null);
		System.out.println(ew + ":" + eh);
		int x1 = (int) (h * (double) sw / sh),
				x2 = (int) (w - h * (double) ew / eh);
		System.out.println(x1 + ":" + x2);

		BufferedImage dest = GraphicsTools.createCompatibleImage(w, h,
				Transparency.TRANSLUCENT);
		Graphics2D g2d = dest.createGraphics();
		g2d.drawImage(startImg, 0, 0, x1, h, null);
		if (x2 > 0)
			g2d.drawImage(endImg, x2, 0, w - x2, h, null);
		if (x2 > x1)
			g2d.drawImage(middleImg, x1 - 11, 0, x2 - x1 + 11, h, null);
		g2d.dispose();
		return dest;
	}

	public static Shape getShape(BufferedImage img)
	{
		if (img == null)
			return null;
		int width = img.getWidth(), height = img.getHeight();
		int[] pixels = PixelsTools.getPixelsFromImage(img);
		int alpha;
		Area area = new Area();
		int t, mw = width - 1;
		for (int i = 0; i < height; i++)
		{
			t = -1;
			for (int j = 0; j < width; j++)
			{
				alpha = (pixels[i * width + j] >> 24) & 0xff;
				if (alpha != 0)
				{
					if (t == -1)
						t = j;
					if (j == mw)
						area.add(new Area(new Rectangle(t, i, j - t, 1)));
				} else if (t != -1)
				{
					area.add(new Area(new Rectangle(t, i, j - t, 1)));
					t = -1;
				}
			}
		}
		return area;
	}

	// 创建旋转图片
	public static BufferedImage rotate(BufferedImage src, double angle)
	{
		if (src == null)
			return null;
		double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
		int w = src.getWidth(), h = src.getHeight();
		int newWidth = (int) Math.floor(w * cos + h * sin),
				newHeight = (int) Math.floor(h * cos + w * sin);
		int transparency = src.getColorModel().getTransparency();
		BufferedImage dest = GraphicsTools.createCompatibleImage(newWidth, newHeight,
				transparency);
		Graphics2D g = dest.createGraphics();
		g.translate((newWidth - w) / 2, (newHeight - h) / 2);
		g.rotate(angle, (double) w / 2, (double) h / 2);
		g.drawRenderedImage(src, null);
		g.dispose();
		return dest;
	}

	// 图片切圆角
	public static BufferedImage clip(Image src, int width, int height,
			int radius)
	{
		if (src == null || width <= 0 || height <= 0)
			return null;
		BufferedImage dest = new BufferedImage(width, height,
				BufferedImage.TYPE_INT_ARGB);
		Graphics2D g = dest.createGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g.fillRoundRect(0, 0, width, height, radius, radius);
		g.setComposite(AlphaComposite.SrcIn);
		g.drawImage(src, 0, 0, width, height, null);
		g.dispose();
		return dest;
	}

	public static BufferedImage clip(Image src, int radius)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		return clip(src, width, height, radius);
	}

	// 图片设置圆角
	public static BufferedImage setRadius(Image src, int radius, int border,
			int padding)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		int canvasWidth = width + padding * 2;
		int canvasHeight = height + padding * 2;

		BufferedImage image = new BufferedImage(canvasWidth, canvasHeight,
				BufferedImage.TYPE_INT_ARGB);
		Graphics2D gs = image.createGraphics();
		gs.setComposite(AlphaComposite.Src);
		gs.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		gs.setColor(Color.WHITE);
		gs.fill(new RoundRectangle2D.Float(0, 0, canvasWidth, canvasHeight,
				radius, radius));
		gs.setComposite(AlphaComposite.SrcAtop);
		gs.drawImage(clip(src, radius), padding, padding, null);
		if (border != 0)
		{
			gs.setColor(Color.GRAY);
			gs.setStroke(new BasicStroke(border));
			gs.drawRoundRect(padding, padding, canvasWidth - 2 * padding,
					canvasHeight - 2 * padding, radius, radius);
		}
		gs.dispose();
		return image;
	}

	public static BufferedImage setRadius(Image src)
	{
		if (src == null)
			return null;
		int width = src.getWidth(null), height = src.getHeight(null);
		if (width <= 0 || height <= 0)
		{
			loadImage(src);
			width = src.getWidth(null);
			height = src.getHeight(null);
			if (width <= 0 || height <= 0)
				return null;
		}
		int radius = (width + height) / 8;
		return setRadius(src, radius, 2, 5);
	}

	/**
	 * 把多张图片合成一张gif
	 */
	public synchronized void imageToGif(BufferedImage[] src, File picFile)
	{
		if (src == null || picFile == null)
			return;
		try
		{
			AnimatedGifEncoder e = new AnimatedGifEncoder();
			e.setRepeat(0);
			e.start(picFile);
			for (BufferedImage image : src)
			{
				e.setDelay(200); // 设置播放的延迟时间
				e.addFrame(image); // 添加到帧中
			}
			e.finish();
		} catch (Exception e)
		{
			System.out.println("imageToGif Failed:");
			e.printStackTrace();
		}
	}

	public synchronized void imageToGif(List<BufferedImage> src, File picFile)
	{
		if (src == null || picFile == null)
			return;
		try
		{
			AnimatedGifEncoder e = new AnimatedGifEncoder();
			e.setRepeat(0);
			e.start(picFile);
			for (BufferedImage image : src)
			{
				e.setDelay(200); // 设置播放的延迟时间
				e.addFrame(image); // 添加到帧中
			}
			e.finish();
		} catch (Exception e)
		{
			System.out.println("imageToGif Failed:");
			e.printStackTrace();
		}
	}

	/**
	 * 图像切割(按指定起点坐标和宽高切割)
	 */
	public static BufferedImage cut(Image src, int x, int y, int width,
			int height)
	{
		CropImageFilter cropFilter = new CropImageFilter(x, y, width, height);
		Image img = Toolkit.getDefaultToolkit().createImage(
				new FilteredImageSource(src.getSource(), cropFilter));
		int transparency = Transparency.OPAQUE;
		if (src instanceof BufferedImage)
			transparency = ((BufferedImage) src).getColorModel()
					.getTransparency();
		BufferedImage dest = GraphicsTools.createCompatibleImage(width, height,
				transparency);
		Graphics g = dest.getGraphics();
		g.drawImage(img, 0, 0, width, height, null); // 绘制切割后的图
		g.dispose();
		return dest;
	}

	/**
	 * 彩色转为黑白
	 */
	public static BufferedImage gray(BufferedImage src)
	{
		if (src == null)
			return null;
		ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
		ColorConvertOp op = new ColorConvertOp(cs, null);
		return op.filter(src, null);
	}

	public static boolean isNormalImage(String fileName)
	{
		String fileExt = TextTools.getFileExt(fileName);
		if (fileExt == null)
			return false;
		fileExt = fileExt.toLowerCase(Locale.ENGLISH);
		for (String ext : pictureExts)
			if (fileExt.equals(ext))
				return true;
		return false;
	}

	public static void loadImage(Image image)
	{
		synchronized (mediaTracker)
		{
			int id = ++mediaTrackerID;
			mediaTracker.addImage(image, id);
			try
			{
				mediaTracker.waitForID(id, 0);
			} catch (InterruptedException e)
			{
				System.out.println("INTERRUPTED while loading Image");
			}
			mediaTracker.statusID(id, false);
			mediaTracker.removeImage(image, id);
		}
	}
}
